﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;

namespace WorldOnFire
{
    public class ABCProjectile : ABCMovingObject
    {
        #region Projectile Data

        public enum eProjectileType
        {
            BULLET,
            FLAK,
            SHELL,
            LASER,
            EMP,
            BLACK_HOLE,
            RELAY,
            BOMB,
            PLASMA,
            MISSILE,
            COUNT
        };

        public void SetProjectileID(eProjectileType _eProjectileID)
        { m_eProjectileID = _eProjectileID; }

        // Projectile Data
        private eProjectileType m_eProjectileID;
        protected float[] m_fDamage;
        protected float[] m_fAreaOfEffect;
        protected float[] m_fSpeed;

        // Lifetime Data
        protected float[] m_fMaximumTime;
        protected float[] m_fTimeSinceFired;

        public float GetDamage(int _nIndex)
        { return m_fDamage[_nIndex]; }

        #endregion Projectile Data

        #region Initialization

        public override void Initialize(int _nObjectCount)
        {
            // Initialize the arrays
            m_fDamage = new float[_nObjectCount];
            m_fAreaOfEffect = new float[_nObjectCount];
            m_fSpeed = new float[_nObjectCount];

            m_fMaximumTime = new float[_nObjectCount];
            m_fTimeSinceFired = new float[_nObjectCount];

            // Initialize the base members
            base.Initialize(_nObjectCount);

            // Initialize rendering data
            m_bOverlay = true;

            // Assign collidable types
            m_CollidableTypeList.Add(eObjectType.HOMEWORLD);
            m_CollidableTypeList.Add(eObjectType.SATELLITE);
        }

        #endregion Initialization

        #region Update and Render

        public override void Update(float _fDeltaTime)
        {
            // Loop through each projectile
            for (int iProjectile = 0; iProjectile < m_nObjectCount; ++iProjectile)
            {
                // If this object is inactive
                if (m_bObjectActive[iProjectile] == false)
                {
                    // Skip this object
                    continue;
                }

                // Update the elapsed time
                m_fTimeSinceFired[iProjectile] += _fDeltaTime;

                // If the projectile has gone beyond its range
                if (m_fTimeSinceFired[iProjectile] > m_fMaximumTime[iProjectile])
                {
                    // Kill the projectile
                    this.KillProjectile(iProjectile);
                }
            }

            base.Update(_fDeltaTime);
        }

        public override bool RespondToCollision(int _nIndex, ABCObject _Object, int _nObjectIndex)
        {
            // Kill the projectile and bail out
            this.KillProjectile(_nIndex);
            return false;
        }

        #endregion Update and Render

        #region Activation and Deactivation

        public void CreateProjectile(ABCTurret _Turret, int _nTurretIndex, Vector3 _vOffset)
        {
            // If there is an unused projectile
            if (this.FindUnusedIndex() == true)
            {
                // Initialize the projectile
                this.InitializeProjectile(m_nInactiveObjectIndex, _Turret, _nTurretIndex, _vOffset);
            }
        }

        public void CreateProjectile(ABCEnemy _Enemy, int _nEnemyIndex, Vector3 _vOffset)
        {
            // If there is an unused projectile
            if (this.FindUnusedIndex() == true)
            {
                // Initialize the projectile
                this.InitializeProjectile(m_nInactiveObjectIndex, _Enemy, _nEnemyIndex, _vOffset);
            }
        }

        protected virtual void InitializeProjectile(int _nProjectileIndex, ABCTurret _Turret, int _nTurretIndex, Vector3 _vOffset)
        {
            // Set the projectile to active
            this.CreateObject(_nProjectileIndex);
            this.ScheduleForActivation(_nProjectileIndex);

            // Reset moving object members
            this.InitializeMovingObject(_nProjectileIndex);

            // Initialize the transform (Turret Transform + Turret Offset * Z-Axis)
            // TODO: ADD SHOT SPREAD, YOU LAZY SON OF A BITCH
            Matrix mTransform = _Turret.GetTransform(_nTurretIndex);
            m_mTransform[_nProjectileIndex] = mTransform;

            mTransform.Translation = Vector3.Zero;
            m_mTransform[_nProjectileIndex].Translation += Vector3.Transform(_vOffset, mTransform);

            // Initialize other members
            m_fSpeed[_nProjectileIndex] = _Turret.GetShotSpeed(_nTurretIndex);
            m_fDamage[_nProjectileIndex] = _Turret.GetDamage(_nTurretIndex);
            m_fAreaOfEffect[_nProjectileIndex] = _Turret.GetAreaOfEffect(_nTurretIndex);

            // Initialize velocity
            m_vVelocity[_nProjectileIndex] = m_fSpeed[_nProjectileIndex] * mTransform.Backward;

            // Calculate the amount of time the projectile should be alive
            // (Time = Range / Speed)
            m_fMaximumTime[_nProjectileIndex] = _Turret.GetRange(_nTurretIndex) / m_fSpeed[_nProjectileIndex];
            m_fTimeSinceFired[_nProjectileIndex] = 0.0f;
        }

        protected virtual void InitializeProjectile(int _nProjectileIndex, ABCEnemy _Enemy, int _nEnemyIndex, Vector3 _vOffset)
        {
            // Set the projectile to active
            this.CreateObject(_nProjectileIndex);
            this.ScheduleForActivation(_nProjectileIndex);

            // Reset moving object members
            this.InitializeMovingObject(_nProjectileIndex);

            // Initialize the transform
            Matrix mTransform = _Enemy.GetTransform(_nEnemyIndex);
            m_mTransform[_nProjectileIndex] = mTransform;

            mTransform.Translation = Vector3.Zero;
            m_mTransform[_nProjectileIndex].Translation += Vector3.Transform(_vOffset, mTransform);

            // Initialize other members
            m_fSpeed[_nProjectileIndex] = _Enemy.GetShotSpeed();
            m_fDamage[_nProjectileIndex] = _Enemy.GetDamage();
            m_fAreaOfEffect[_nProjectileIndex] = _Enemy.GetAreaOfEffect();

            // Initialize velocity
            m_vVelocity[_nProjectileIndex] = m_fSpeed[_nProjectileIndex] * mTransform.Backward;

            // Calculate the amount of time the projectile should be alive
            // (Time = Range / Speed)
            m_fMaximumTime[_nProjectileIndex] = _Enemy.GetRange() / m_fSpeed[_nProjectileIndex];
            m_fTimeSinceFired[_nProjectileIndex] = 0.0f;
        }

        protected virtual void KillProjectile(int _nProjectileIndex)
        {
            // Set the projectile to inactive
            this.ScheduleForDeactivation(_nProjectileIndex);
        }

        #endregion Activation and Deactivation
    }
}
